#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
"""
Path store for important files and folders.

Modified from Pysol instance to hold all important locations and with some
methods moved to their respective module. It is also now an object that can
be imported into modules needing location info.
"""

import os
import logging

LOGGER = logging.getLogger('PySolFC.Utillib.PathDB')

from ..settings import DATA_DIRS, IMAGE_EXTENSIONS, PACKAGE

IMAGE_EXT_ITER = lambda n: ("{0}{1}".format(n, x)  for x in IMAGE_EXTENSIONS)
NJ_PATH = lambda p: os.path.normpath(os.path.join(*p))


class __PathDB(object):
    """
    Path store for important files and folders.
    """
    dn = {}
    fn = {}

    def __init__(self):
        """
        __init__() -> None

        Init finder data.

        Init default **config** dir and call **_init_paths**.
        """
        self._init_paths()
        config = self.dn['config']
        for path in ([config, self.dn['savegames']] +
                     [NJ_PATH([config, r])
                        for r in ['music', 'tiles', 'cardsets', 'plugins']] +
                     [NJ_PATH([config, 'tiles', t])
                        for t in ['stretch', 'save-aspect']]):
            if not os.path.exists(path):
                try:
                    os.makedirs(path)
                except (IOError, OSError):
                    LOGGER.error('Unable to make path %s', path)

    def init(self, argv0, files=None):
        """
        init(argv0:str, files:seq='pysol.ico') -> None

        Init finder data.

        Init default **data** dir and call **_init_files**.
        """
        files = files or ['pysol.ico']
        files = files if isinstance(files, (tuple, list,)) else [files]
        # startup path
        head = os.path.dirname(argv0)
        head = os.curdir if not head else head
        d_path = []
        for path in (os.path.abspath(p) for p in [head] + DATA_DIRS if p):
            path = NJ_PATH([path, 'data'])
            if path and (path not in d_path) and os.path.isdir(path):
                nfiles = [f for f in files
                             if os.path.isfile(NJ_PATH([path, f]))]
                if len(nfiles) == len(files):
                    self.dn['data'] = path
                    break
                d_path.append(path)
        else:
            raise OSError('DataLoader could not find {0!s}.'.format(files))
        self._init_files()

    def _init_paths(self):
        """
        _init_files() -> None

        Init dir locations.

        Assign full path of important dir locations used to **dn** dict.
        """
        config = NJ_PATH([os.path.expanduser('~'), '.config', PACKAGE])
        self.dn = {'data': None,
                   'config': config,
                   'plugins': NJ_PATH([config, 'plugins']),
                   'savegames': NJ_PATH([config, 'savegames']),
                   'maint': NJ_PATH([config, 'maint']),
                   'user': os.path.expanduser('~')}

    def _init_files(self):
        """
        _init_files() -> None

        Init file locations.

        Assign full path of important file locations used to **fn** dict.
        """
        base, conf = self.dn['data'], self.dn['config']
        self.fn = {'opt_conf': NJ_PATH([conf, 'options.cfg']),
                   'opt_spec': NJ_PATH([base, 'config.cfg']),
                   'stats': NJ_PATH([conf, 'statistics.dat']),
                   'holdgame': NJ_PATH([conf, 'holdgame.dat']),
                   'notes': NJ_PATH([conf, 'comments.dat']),
                   'icon': NJ_PATH([base, 'pysol{}'.format('.ico'
                                                            if os.name == 'nt'
                                                            else '.xbm')])}

    def __locate(self, func, filename, subdirs=None, do_raise=True):
        """
        __locate(func:func(str)->bool, name:str, subdirs:seq(str ...)='',
          do_raise:bool=True) -> str

        Find a file / directory.

        Returns full path of **name** of **func** condition found within the
        chosen data directory and its **subdirs**.  Raises **OsError** if
        nothing can be found for **func** path type.
        """
        subdirs = subdirs or ['']
        subdirs = subdirs if isinstance(subdirs, (tuple, list,)) else [subdirs]

        for m_dir in [self.dn['data'], self.dn['config']]:
            for s_dir in subdirs:
                path = NJ_PATH([m_dir, s_dir, filename])
                if func(path):
                    return path

        if do_raise:
            raise OSError('DataLoader could not find {0}.'.format(filename))

    def find_file(self, name, subdirs=None, do_raise=True):
        """
        find_file(name:str, subdirs:seq(str ...)=[''], do_raise:bool=True)
          -> str

        Find a file.

        Returns full path of **name** that is a file found within the chosen
        data dir and its **subdirs**. Calls **__locate** with all args along
        with a file condition.
        """
        return self.__locate(os.path.isfile, name, subdirs, do_raise)

    def find_image(self, name, subdirs=None):
        """
        find_image(name:str, subdirs:seq(str ...)=['']) -> str

        Find an image.

        Returns image of **name** found within the chosen data directory and its
        **subdirs** of any **IMAGE_EXTENSIONS**. Raises **OsError** if nothing
        can be found.
        """
        for path in IMAGE_EXT_ITER(name):
            i_path = self.__locate(os.path.isfile, path, subdirs,
                                   do_raise=False)
            if i_path:
                return i_path
        raise OSError('DataLoader could not find {0}.'.format(name))

    def find_dir(self, filename, subdirs=None, do_raise=True):
        """
        find_dir(name:str, subdirs:seq(str ...)=[''], do_raise:bool=True)
          -> str

        Find a dir.

        Returns full path of **name** that is a dir found within the chosen
        data dir and its **subdirs**. Calls **__locate** with all args along
        with a dir condition.
        """
        return self.__locate(os.path.isdir, filename, subdirs, do_raise)


PATH_DB = __PathDB()